part of 'index.dart';

class ChatProvider with ChangeNotifier {
  BuildContext context;
  final pannelController = PannelController();
  StreamSubscription<List<EMMessage>>? _messageSubscription;
  final input = TextEditingController();
  final focus = FocusNode();
  final EMConversation? conversation;
  chat.UserInfo? user;
  List<EMMessage> messageList = [];
  Map<String, Uint8List?> thumbnailMap = {};
  List<ImGitfModel> gifts = [];
  List<ImGitfWrapperModel> wrappers = [];
  ImGitfModel? gift;
  int giftCount = 1;
  final _scrollController = ScrollController();
  String? startMsgId;
  bool _noMore = false;
  final int _limit = 20;
  final dio = Dio();
  final refreshController = EasyRefreshController(
    controlFinishRefresh: true,
    controlFinishLoad: true,
  );
  //
  String playingMsgId = '';
  final AudioPlayer audioPlayer = AudioPlayer();
  final balance = ValueNotifier<int?>(null);
  late StreamSubscription<bool> keyboardSubscription;

  ChatProvider(this.context, this.conversation, this.user) {
    final cid = conversation?.id;
    if (user == null && cid != null) {
      ImManager.of.fetchUserInfoById(cid).then((value) {
        user = value;
      });
    }
    _getBalance();
    _initMessageListener();
    _getMessageList();
    _initGifts();
    ImAPI.getImStatus(cid!);
    _messageSubscription =
        ImManager.of.messageStream.listen(_onMessageReceived);
    _scrollController.addListener(() {
      Tools.unfocus();
      pannelController.hide();
    });

    audioPlayer.playerStateStream.listen((state) {
      debugPrint(state.toString());
      if (state.processingState == ProcessingState.completed) {
        playingMsgId = '';
        notifyListeners();
      }
    });
    final keyboardVisibilityController = KeyboardVisibilityController();
    keyboardSubscription =
        keyboardVisibilityController.onChange.listen((bool visible) {
      if (!visible) {
        final type = pannelController.pannelType;
        if (type == PannelType.keyboard) {
          pannelController.hide();
        }
      }
    });
  }

  void _getBalance() async {
    final value = await ImAPI.getBalance();
    balance.value = value;
  }

  void _initMessageListener() {
    EMClient.getInstance.chatManager.addMessageEvent(
      "chat_send_message_change_listener",
      ChatMessageEvent(
        onSuccess: (msgId, msg) {
          messageList.removeWhere((e) => e.msgId == msgId);
          messageList.insert(0, msg);
          notifyListeners();
          debugPrint("==IM==:消息上传或下载成功($msgId)");
        },
        onProgress: (msgId, progress) {
          debugPrint("==IM==: 消息上传或下载中($msgId)$progress");
        },
        onError: (msgId, msg, error) {
          debugPrint(
              "==IM==:发送消息失败, code: ${error.code}, desc: ${error.description}");
        },
      ),
    );
    EMClient.getInstance.chatManager.addEventHandler(
      "receive_gitf_message_listener",
      EMChatEventHandler(
        onMessagesReceived: (messages) {
          for (var msg in messages) {
            if (msg.from != conversation?.id) continue;
            if (msg.body.type == MessageType.CUSTOM) {
              final body = msg.body as EMCustomMessageBody;
              if (body.event == CustomMessageType.gift.value) {
                final params = body.params;
                if (params == null) continue;
                final obj = params['objUrl'];
                if (obj?.startsWith('http') == true) {
                  showGift(obj!);
                }
              }
            }
          }
        },
      ),
    );
  }

  void _initGifts() {
    final results = ImAPI.giftLocalList();
    gifts = results.$1;
    wrappers = results.$2;
  }

  void setGiftCount(int count) {
    if (count == giftCount) return;
    giftCount = count;
    notifyListeners();
  }

  List<ImGitfModel> getGifts(ImGitfWrapperModel wrapper) {
    final ids = wrapper.giftVos.map((e) => e.id).toList();
    final matchedGifts = gifts.where((gift) => ids.contains(gift.id)).toList();
    return matchedGifts;
  }

  void _onMessageReceived(List<EMMessage> messages) {
    final conversationId = conversation?.id;
    if (conversationId == null) return;
    final conversationMessages =
        messages.where((msg) => msg.conversationId == conversationId).toList();
    if (conversationMessages.isNotEmpty) {
      messageList.insertAll(0, conversationMessages);
      ImManager.of.clearUnread(conversationId);
      notifyListeners();
    }
  }

  Future<void> _getMessageList({String? start}) async {
    final conversationId = conversation?.id;
    if (conversationId == null) return;
    final result = await ImManager.of.loadLocalHistoryMessage(
      conversationId,
      startMsgId: start ?? startMsgId,
      limit: _limit,
    );
    messageList.addAll(result);
    messageList.sort((a, b) => b.serverTime.compareTo(a.serverTime));
    if (result.isNotEmpty) startMsgId = result.first.msgId;
    if (result.length < _limit) _noMore = true;
    notifyListeners();
  }

  void onLoading() async {
    if (_noMore) {
      refreshController.finishLoad(IndicatorResult.noMore);
      return;
    }
    try {
      await _getMessageList();
      refreshController.finishLoad();
    } catch (error) {
      refreshController.finishLoad(IndicatorResult.fail);
    }
  }

  void sendTextMessage() async {
    final conversationId = conversation?.id;
    final content = input.text;
    input.clear();
    if (conversationId == null || content.isEmpty) return;

    final message = EMMessage.createTxtSendMessage(
      targetId: conversationId,
      content: content,
    );
    messageList.insert(0, message);
    notifyListeners();
    final result = await ImManager.of.sendTextMessage(
      targetId: conversationId,
      message: content,
      onError: () {},
    );
    _handleMessage(message, result);
  }

  void _handleMessage(EMMessage before, EMMessage? after) {
    if (after != null) {
      messageList.remove(before);
      messageList.insert(0, after);
    }
  }

  // void sendImageMessage(File file) async {
  //   final conversationId = conversation?.id;
  //   if (conversationId == null) return;
  //   final path = file.path;
  //   if (path.isEmpty) return;
  //   final imageFile = File(path);
  //   final bytes = await imageFile.readAsBytes();
  //   final image = await decodeImageFromList(bytes);
  //   final width = image.width;
  //   final height = image.height;
  //   final message = EMMessage.createImageSendMessage(
  //     targetId: conversationId,
  //     filePath: path,
  //   );
  //   messageList.insert(0, message);
  //   notifyListeners();

  //   final result = await ImManager.of.sendImageMessage(
  //     targetId: conversationId,
  //     filePath: path,
  //     width: width.toDouble(),
  //     height: height.toDouble(),
  //     onError: () {},
  //   );
  //   _handleMessage(message, result);
  // }
  void sendImageMessage(AssetEntity entity) async {
    final conversationId = conversation?.id;
    if (conversationId == null) return;
    final file = await entity.file;
    if (file == null) return;
    final path = file.path;
    if (path.isEmpty) return;
    final imageFile = File(path);
    final bytes = await imageFile.readAsBytes();
    final image = await decodeImageFromList(bytes);
    final width = image.width;
    final height = image.height;

    final thumbnailData = await entity.thumbnailData;
    final directory = await getApplicationDocumentsDirectory();
    final thumbnailPath =
        '${directory.path}/${DateTime.now().millisecondsSinceEpoch}_thumb.jpg';
    if (thumbnailData != null) {
      await File(thumbnailPath).writeAsBytes(thumbnailData);
    }

    final message = EMMessage.createImageSendMessage(
      targetId: conversationId,
      filePath: path,
    );
    messageList.insert(0, message);
    notifyListeners();

    final result = await ImManager.of.sendImageMessage(
      targetId: conversationId,
      filePath: path,
      width: width.toDouble(),
      height: height.toDouble(),
      thumbnailLocalPath: thumbnailPath,
      onError: () {},
    );
    _handleMessage(message, result);
  }

  void sendVideoMessage(AssetEntity entity) async {
    final conversationId = conversation?.id;
    if (conversationId == null) return;
    final file = await entity.file;
    if (file == null) return;
    final path = file.path;

    // 保存缩略图到本地
    final thumbnailData = await entity.thumbnailData;
    final directory = await getApplicationDocumentsDirectory();
    final thumbnailPath =
        '${directory.path}/${DateTime.now().millisecondsSinceEpoch}_thumb.jpg';
    if (thumbnailData != null) {
      await File(thumbnailPath).writeAsBytes(thumbnailData);
    }

    final message = EMMessage.createVideoSendMessage(
      targetId: conversationId,
      filePath: path,
      width: double.tryParse('${entity.width}'),
      height: double.tryParse('${entity.height}'),
      duration: entity.duration,
      thumbnailLocalPath: thumbnailPath,
    );
    messageList.insert(0, message);

    notifyListeners();
    debugPrint('发送视频消息本地视频路径: $path');
    final result = await ImManager.of.sendVideoMessage(
      targetId: conversationId,
      filePath: path,
      width: double.tryParse('${entity.width}'),
      height: double.tryParse('${entity.height}'),
      duration: entity.duration,
      thumbnailLocalPath: thumbnailPath,
      onError: () {},
    );
    _handleMessage(message, result);
  }

  void sendVoiceMessage(String path, int duration) async {
    final conversationId = conversation?.id;
    if (conversationId == null) return;
    final message = EMMessage.createVoiceSendMessage(
      targetId: conversationId,
      filePath: path,
      duration: duration,
    );
    messageList.insert(0, message);
    notifyListeners();
    final result = await ImManager.of.sendVoiceMessage(
      targetId: conversationId,
      filePath: path,
      duration: duration,
      onError: () {},
    );
    _handleMessage(message, result);
  }

  void sendGiftMessage() async {
    final conversationId = conversation?.id;
    if (conversationId == null || gift == null) return;
    String? image = gift?.objectUrl;
    String? obj = gift?.objectGifUrl;
    var giftId = gift?.id;
    if (image == null || giftId == null) return;
    final result = await ImAPI.sendGift(
      count: giftCount,
      id: giftId,
      userId: conversationId,
    );
    if (!result) return;
    _getBalance();
    if (obj != null) showGift(obj);
    final message = EMMessage.createCustomSendMessage(
      targetId: conversationId,
      event: 'gift',
      params: {
        'type': 'gift',
        'imageUrl': image,
        'objUrl': obj ?? '',
        'count': giftCount.toString(),
      },
    );
    messageList.insert(0, message);
    notifyListeners();
    final value = await ImManager.of.sendGiftMessage(
      targetId: conversationId,
      imageUrl: image,
      objUrl: obj ?? '',
      count: giftCount,
      onError: () {},
    );
    _handleMessage(message, value);
  }

  void showGift(String obj) {
    if (context.mounted) {
      showDialog(
        context: context,
        barrierColor: Colors.transparent,
        barrierDismissible: false,
        builder: (_) => MessageGiftSvga(
          obj,
          callback: () {
            if (Navigator.of(context).canPop()) {
              Navigator.of(context).pop();
            }
          },
        ),
      );
    }
  }

  void recallMessage(String messageId) async {
    final result = await ImManager.of.recallMessage(messageId);
    if (result) {
      messageList.removeWhere((e) => e.msgId == messageId);
      notifyListeners();
    }
  }

  void deleteMessage(String messageId) async {
    final conversationId = conversation?.id;
    if (conversationId == null) return;
    messageList.removeWhere((e) => e.msgId == messageId);
    notifyListeners();
    ImManager.of.deleteMessage(
      conversationId: conversationId,
      messageId: messageId,
    );
  }

  void playAudio(String msgId, String? remote, String local) async {
    if ((remote == null || remote.isEmpty) && local.isEmpty) return;
    if (msgId == playingMsgId) {
      audioPlayer.stop();
      playingMsgId = '';
      notifyListeners();
      return;
    }
    if (audioPlayer.playing) audioPlayer.stop();
    playingMsgId = msgId;
    if (local.isNotEmpty) {
      try {
        final source = AudioSource.uri(Uri.parse('file://$local'));
        await audioPlayer.setAudioSource(source);
        audioPlayer.play();
      } catch (e) {
        debugPrint('播放本地音频失败: $e');
        if (remote != null && remote.startsWith('http')) {
          final directory = await getApplicationDocumentsDirectory();
          final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
          final savePath = '${directory.path}/$timestamp.m4a';
          final resp = await dio.downloadUri(Uri.parse(remote), savePath);
          final result = resp.statusCode == 200;
          debugPrint('下载远程音频${result ? '成功' : '失败'}: $savePath');
          if (result) {
            final source = AudioSource.uri(Uri.parse('file://$savePath'));
            await audioPlayer.setAudioSource(source);
            audioPlayer.play();
          }
        }
      }
    } else if (remote != null && remote.startsWith('http')) {
      final source = AudioSource.uri(Uri.parse(remote));
      await audioPlayer.setAudioSource(source);
      audioPlayer.play();
    }
    notifyListeners();
  }

  void jumpRecharge() {
    CommonWebView.show(
      context,
      "https://h5web.yahabbi.com/wallet/index.html?hideNavi=1&hideBottomSafeArea=1&is_full_screen=1",
    ).then((value) {
      _getBalance();
    });
  }

  @override
  void dispose() {
    audioPlayer.dispose();
    _messageSubscription?.cancel();
    EMClient.getInstance.chatManager.removeMessageEvent(
      "receive_gitf_message_listener",
    );
    EMClient.getInstance.chatManager.removeMessageEvent(
      "chat_send_message_change_listener",
    );
    keyboardSubscription.cancel();
    focus.dispose();
    input.dispose();
    super.dispose();
  }
}
